package com.radar.io.radar346;

import cn.hutool.core.date.DateUtil;
import com.radar.algorithm.Cacl;
import com.radar.algorithm.MathCommon;
import com.radar.common.*;
import com.radar.exception.RadarCaclError;
import com.radar.exception.RadarDecodeError;
import com.radar.exception.RadarVisualizeError;
import com.radar.io.BaseRadr;
import com.radar.io.RadarGridData;
import com.radar.utils.BitConverter;
import com.radar.visualize.PolarMap;
import com.radar.visualize.RasterMap;
import com.radar.visualize.ThematicMap;
import org.meteoinfo.global.Extent;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.stream.IntStream;

public class Product346 extends BaseRadr {

    @Override
    public void dispose() {

    }

    public class RADARPERFORMANCEPARAM_A {
        public int size = 30 + 24;

        public int AntennaG;
        public int BeamH;
        public int BeamL;
        public byte Polarizations;
        public short SideLobe;
        public int Power;
        public int WaveLength;
        public int LineA;
        public short LineMinPower;
        public int ClutterP;
        public int ClutterS;
        public byte VelocityP;
        public byte FilterP;
        public byte FilterS;
        public byte NoiseT;
        public byte intensityR;
        //24
        public byte[] Reserved;

        public void parse(byte[] b) {
            int index = 0;
            AntennaG = BitConverter.toInt32(b, index);
            index += 4;
            BeamH = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            BeamL = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            Polarizations = b[index];
            index++;
            SideLobe = BitConverter.toInt16(b, index);
            index += 2;
            Power = BitConverter.toInt32(b, index);
            index += 4;
            WaveLength = BitConverter.toInt32(b, index);
            index += 4;
            LineA = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            LineMinPower = BitConverter.toInt16(b, index);
            index += 2;
            ClutterP = (0xff & b[index]);
            index += 1;
            ClutterS = (0xff & b[index]);
            index += 1;
            VelocityP = b[index];
            index++;
            FilterP = b[index];
            index++;
            FilterS = b[index];
            index++;
            NoiseT = b[index];
            index++;
            intensityR = b[index];
            index++;
            Reserved = new byte[24];
            System.arraycopy(b, index, Reserved, 0, Reserved.length);
        }
    }

    public class RADARDATAFILEHEADER {

        public RADARPERFORMANCEPARAM_A RadarPerformanceInfo;
        public POLAROBSERVATIONPARAM RadarObservationInfo;
        int size = 30 + 24 + 63 + 24 + 24;
        //24
        public byte[] Reserved;

        public void parse(byte[] b) throws UnsupportedEncodingException {
            int index = 0;
            RadarPerformanceInfo = new RADARPERFORMANCEPARAM_A();
            byte[] bytdata = new byte[RadarPerformanceInfo.size];
            System.arraycopy(b, index, bytdata, 0, bytdata.length);
            RadarPerformanceInfo.parse(bytdata);
            index += RadarPerformanceInfo.size;

            RadarObservationInfo = new POLAROBSERVATIONPARAM();
            bytdata = new byte[RadarObservationInfo.size];
            System.arraycopy(b, index, bytdata, 0, bytdata.length);
            RadarObservationInfo.parse(bytdata);
            index += RadarObservationInfo.size;

            Reserved = new byte[24];
            System.arraycopy(b, index, Reserved, 0, Reserved.length);
        }
    }

    public class POLAROBSERVATIONPARAM {
        public int size = 63 + 24;

        //16
        public String Lon;
        public String Lat;
        public byte ProductNumber;
        public byte LayerNumber;
        public short HeightAngle;
        public byte WeatherMode;
        public int SYear;
        public byte SMonth;
        public byte SDay;
        public byte SHour;
        public byte SMinute;
        public byte SSecond;
        public byte Calibration;
        public byte Ambiguousp;
        public int PRF1;
        public int PRF2;
        public byte Filter;
        public int PluseW;
        public int MaxV;
        public int MaxL;
        public int BinWidth;
        public int BinNumber;
        public int RecodeNumber;
        //24
        public byte[] Reserved;

        public void parse(byte[] b) throws UnsupportedEncodingException {
            int index = 0;
            Lon = new String(Arrays.copyOfRange(b, index, index + 16), "GBK");
            index += 16;
            Lat = new String(Arrays.copyOfRange(b, index, index + 16), "GBK");
            index += 16;
            ProductNumber = b[index];
            index++;
            LayerNumber = b[index];
            index++;
            HeightAngle = BitConverter.toInt16(b, index);
            index += 2;
            WeatherMode = b[index];
            index++;
            SYear = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            SMonth = b[index];
            index++;
            SDay = b[index];
            index++;
            SHour = b[index];
            index++;
            SMinute = b[index];
            index++;
            SSecond = b[index];
            index++;
            Calibration = b[index];
            index++;
            Ambiguousp = b[index];
            index++;
            PRF1 = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            PRF2 = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            Filter = b[index];
            index++;
            PluseW = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            MaxV = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            MaxL = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            BinWidth = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            BinNumber = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            RecodeNumber = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            Reserved = new byte[24];
            System.arraycopy(b, index, Reserved, 0, Reserved.length);
        }
    }

    public class DATA {
        public int size = 2 + 1024 * 2;
        public int Azi;
        //1024
        public int[] data;

        public void parse(byte[] b) {
            int index = 0;
            Azi = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            data = new int[1024];
            for (int i = 0; i < 1024; i++) {
                data[i] = (BitConverter.toInt16(b, index) & 0x0FFFF);
//                data[i] = BitConverter.toInt16(b, index);
                index += 2;
            }
        }
    }

    public class DATA1 {
        //        public int size = 2 + 1024 * 2;
//        public int size = 2 + 1024 * 2;
        public int Azi;
        //1024
        public int[] data;

        public void parse(byte[] b) throws UnsupportedEncodingException {
            data = new int[1024];
//            ByteBuffer bb = ByteBuffer.wrap(b);
//            Azi = bb.getShort() & 0x0FFFF;
//            for (int i = 0; i < 1024; i++) {
//                data[i] = bb.get() & 0xFF;
//                bb.get();
//            }
            int index = 0;
            Azi = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;


            for (int i = 0; i < 1024; i++) {
                data[i] = b[index];
                index += 1;
            }
        }
    }

    public int Bins;

    public int BinLength;

    public int Records;

    public double MaxL;

    public double[] azi;

    public double[][] data;

    public double lon;

    public double lat;

    public Date dateTime;

    public RADARDATAFILEHEADER header;

    public void parse(String file, ProductType productType) throws RadarDecodeError {
        super.parse(file);
        RADARDATAFILEHEADER header = new RADARDATAFILEHEADER();
        int hLen = header.size;
        int index = 0;
        byte[] bytdata = new byte[hLen];
        try {
            System.arraycopy(bytes, index, bytdata, 0, bytdata.length);
            index += bytdata.length;
            header.parse(bytdata);
            this.header = header;
            GregorianCalendar gc = new GregorianCalendar();

            String format = header.RadarObservationInfo.SYear + "-" + (header.RadarObservationInfo.SMonth < 10 ? "0" +
                    header.RadarObservationInfo.SMonth :
                    header.RadarObservationInfo.SMonth) + "-" +
                    (header.RadarObservationInfo.SDay < 10 ? "0" + header.RadarObservationInfo.SDay : header.RadarObservationInfo.SDay);
            Date date = DateUtil.parse(format, DateConstants.DATE_FORMAT_YY_MM_DD);
            gc.setTime(date);
            gc.set(GregorianCalendar.HOUR_OF_DAY, header.RadarObservationInfo.SHour);
            gc.set(GregorianCalendar.MINUTE, header.RadarObservationInfo.SMinute);
            gc.set(GregorianCalendar.SECOND, header.RadarObservationInfo.SSecond);

            this.dateTime = gc.getTime();
            this.Records = header.RadarObservationInfo.RecodeNumber;
            this.Bins = header.RadarObservationInfo.BinNumber;
            this.BinLength = (int) header.RadarObservationInfo.BinWidth / 10;
            this.MaxL = header.RadarObservationInfo.MaxL * 10;
            double MaxV = header.RadarObservationInfo.MaxV * 10;
            this.data = new double[Records][Bins];
            this.azi = new double[Records];
            for (int i = 0; i < Records; i++) {
                this.azi[i] = -999.0;
            }
            MathCommon.fill(this.data);
            String split[] = header.RadarObservationInfo.Lon.split("/");
            lon = RadarSite.Dms2D(split[0].replace("E", "").replace("W", "").replace("S", "").replace("N", "") + "°" + split[1] + "'" + split[2] + "\"");
            split = header.RadarObservationInfo.Lat.split("/");
            lat = RadarSite.Dms2D(split[0].replace("E", "").replace("W", "").replace("S", "").replace("N", "") + "°" + split[1] + "'" + split[2] + "\"");

            for (int i = 0; i < Records; i++) {
                DATA data = new DATA();
                bytdata = new byte[data.size];
//                bytdata = new byte[1024 + 2];
                System.arraycopy(bytes, index, bytdata, 0, bytdata.length);
                data.parse(bytdata);
                index += data.size;
//                index += 1026;
                this.azi[i] = (double) (int) data.Azi / 100.0;
                if (productType == ProductType.CR || productType == ProductType.REF) {
//                    DATA1 data1 = new DATA1();
//                    data1.parse(bytdata);
//                    this.azi[i] = (double) (int) data1.Azi / 100.0;
                    for (int j = 0; j < Bins; j++) {
                        double d = (double) ((byte) data.data[j]);
                        this.data[i][j] = (double) ((d - 64)) / 2.0;
//                        this.data[i][j] = d;
//                        this.data[i][j] = data1.data[j] / 1000.0;
                        this.data[i][j] = this.data[i][j] < 0 ? GisConstants.UNDEF : this.data[i][j];
                    }
                }
                if (productType == ProductType.ET || productType == ProductType.EB) {
                    for (int j = 0; j < Bins; j++) {
                        if (data.data[j] != Short.MAX_VALUE && data.data[j] != 0) {
                            this.data[i][j] = data.data[j] / 1000.0;
                        }
                    }
                }
                if (productType == ProductType.VIL) {
                    for (int j = 0; j < Bins; j++) {
                        if (data.data[j] != Short.MAX_VALUE && data.data[j] != 0) {
                            this.data[i][j] = data.data[j] / 100.0;
                        }
                    }
                }
                if (productType == ProductType.VEL || productType == ProductType.SW) {
                    for (int j = 0; j < Bins; j++) {
                        if (data.data[j] != Short.MAX_VALUE && data.data[j] != 0) {
//                            this.data[i][j] = (data.data[j] - Short.MAX_VALUE) / 1000;

//                            this.data[i][j] = data.data[j] - Short.MAX_VALUE;
                            this.data[i][j] = data.data[j] / 1000.0;
//                            this.data[i][j] = data.data[j] - 32896;
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public RadarGridData project(ProductType productType) {
        ProductType t = productType == ProductType.CR || productType == ProductType.REF ? ProductType.CR : ProductType.VEL;
        byte[][] refs = MathCommon.Code(this.data, t);
        byte[][] gridppi = Cacl.gridppi(azi, refs, t);
        double resoultion = this.BinLength / 1000.0;
        RadarGridData project = Cacl.project(gridppi, 0, this.lon, this.lat, resoultion, 0.01);
        return project;
    }

    public RadarGridData gridppi(ProductType productType) {
        ProductType t = productType == ProductType.CR || productType == ProductType.REF ? ProductType.CR : ProductType.VEL;
        double[][] gridppi = Cacl.gridppi(azi, this.data, null);
        RadarGridData radarGridData = new RadarGridData();
        radarGridData.data = gridppi;

        double lon = this.lon;
        double lat = this.lat;
        double res = this.BinLength;
        double ele = 0;
        double distance = this.data[0].length * res;
        distance = Math.cos(ele * Const.DEG2RAD) * distance;
        Extent ppiExtent = Common.getExtentRadius(lon, lat, distance);
        radarGridData.xArray = new double[radarGridData.data[0].length];
        radarGridData.yArray = new double[radarGridData.data.length];
        IntStream.range(0, radarGridData.xArray.length).forEach(i -> radarGridData.xArray[i] = ppiExtent.minX + i * ppiExtent.getWidth() / radarGridData.data[0].length);
        IntStream.range(0, radarGridData.yArray.length).forEach(i -> radarGridData.yArray[i] = ppiExtent.minY + i * ppiExtent.getHeight() / radarGridData.data.length);
        return radarGridData;
    }


    public RadarGridData projectNoZip() {
        double[][] gridppi = Cacl.gridppi(azi, this.data, null);
        double resoultion = this.BinLength / 1000.0;
        RadarGridData project = Cacl.project(gridppi, 0, this.lon, this.lat, resoultion, 0.01);
        return project;
    }

    public static void main(String[] args) throws RadarVisualizeError, RadarCaclError, IOException, RadarDecodeError {
//        CinradRadar cinradRadar = new CinradRadar();
//        cinradRadar.parse("/Users/xx/DeskTop/346F/LD20180428111124005.VT346", CinradType.RADAR_382);
//        Product346 product346 = new Product346();
//        product346.parse("Z:\\tmp\\radar\\20230613\\MAXREF\\20230613_172418.00.010.005.0.bz2", ProductType.CR);
        BufferedImage bufferedImage;
        String f = "X:\\data\\hjs\\【数据样本】20231121\\yuntu\\leidatu\\CRO\\P20230222074653.CR0";

        Product346 product346 = new Product346();
        product346.parse(f, ProductType.CR);

        bufferedImage = new PolarMap(null).simplePolarProduct(PolarMap.buildPolarInfo(0, ProductType.REF).backColor(ThematicMap.nullColor), product346.data, product346.azi);
//        bufferedImage = new RasterMap(null).drawSingleRaster(product346.data, "RVD", ThematicMap.nullColor);
        ImageIO.write(bufferedImage, "png", new File(f + ".png"));

//        RadarGridData project = product346.project(ProductType.REF);
//        RasterMap rasterMap = new RasterMap(null);
//        BufferedImage bufferedImage = rasterMap.drawSingleRaster(MathCommon.decode(project.radarData, ProductType.REF), ProductType.CR);
//        PolarMap polarMap = new PolarMap(null);
//        BufferedImage bufferedImage = polarMap.simplePolar(PolarMap.buildPolarInfo(0, ProductType.SW));
//        BufferedImage bufferedImage =
//                polarMap.simplePolarProduct(
//                        PolarMap.buildPolarInfo(0, ProductType.CR)
//                                .backColor(new Color(0, 0, 0, 0))
//                        , product346.data, product346.azi);
    }
}
